/*
 * @Author: zhanyinjia
 * @Date: 2022-07-10 14:51:13
 * @LastEditTime: 2022-07-11 23:14:53
 * @LastEditors: zhanyinjia
 * @Description:
 * @FilePath: \ts\4-decorator.ts
 */
// 类的装饰器（语法糖）
// 只能装饰类，不能装饰函数，因为函数会变量提升
// 装饰类可以给类扩展功能,需要开启experimentalDecorators:true

//es5中高阶函数实现装饰器的功能
/* class Person { }

function decorator(target: any) {
    target.prototype.say = function () { console.log('say') }
}

decorator(Person)

let p1: any = new Person();
p1.say(); */

//----------------------------------------------------------------

// 装饰类  参数只能有一个，就是这个要被装饰的类
/* function addSay(target: any) {
    target.prototype.say = function () { console.log('say') }
}

@addSay
class Person {
    say!: Function    //这里可以用namespace做扩展，后期说到namespace再说
}
let person = new Person
person.say(); */

//----------------------------------------------------------------

// 装饰类中的属性  参数有2个
// 装饰属性可以对属性的内容进行改写，装饰的如果是实例属性则target指向类的原型，装饰的如果是静态属性则target指向类本身
/* function toUpperCase(target: any, key: string) {
    console.log(1);
    console.log(target);

    let value = target[key];
    Object.defineProperty(target, key, {
        get() {
            return value.toUpperCase();
        },
        set(newValue) {
            value = newValue
        }
    })
}
function double(target: any, key: string) {
    console.log(2);
    console.dir(target);

    let value = target[key];
    Object.defineProperty(target, key, {
        get() {
            return value * 2;
        },
        set(newValue) { value = newValue }
    })
}
class Person {
    @toUpperCase
    name: string = 'zhangsan'
    @double
    static age: number = 10;
    getName() {
        return this.name;
    }
}
let person = new Person();
console.log(person.getName(), Person.age) */

//----------------------------------------------------------------

// 装饰类中的方法
/* function noEnum(target: any, key: string, descriptor: PropertyDescriptor) {
    //descriptor  => value configurable writable enumberable
    console.log(descriptor)
    descriptor.enumerable = false;
}
class Person {
    name: string = 'zhangsan'
    static age: number = 10;
    @noEnum
    getName() {
        return this.name;
    }
    say() { }
}

let person = new Person();
console.log(person); // getName 不可枚举
for(let key in person){
  console.log(key);
}
console.log(Object.keys(Person.prototype)); */

//----------------------------------------------------------------

// 装饰类中的参数
/* function addPrefix(target: any, key: string, paramIndex: number) {
    console.log(target, key, paramIndex); // Person.prototype getName  0 
}
class Person {
    name: string = '张三'
    static age: number = 10;
    prefix!: string
    getName(@addPrefix prefix: string) {
        return this.name;
    }
} */